﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;

namespace StatelyCompiler
{
    public static class StringExtensions
    {
        #region Strip
        /// <summary>
        /// Strip a string of the specified character.
        /// </summary>
        /// <param name="s">the string to process</param>
        /// <param name="char">character to remove from the string</param>
        /// <example>
        /// string s = "abcde";
        /// 
        /// s = s.Strip('b');  //s becomes 'acde;
        /// </example>
        /// <returns></returns>
        public static string Strip(this string s, char character)
        {
            s = s.Replace(character.ToString(), "");

            return s;
        }

        /// <summary>
        /// Strip a string of the specified characters.
        /// </summary>
        /// <param name="s">the string to process</param>
        /// <param name="chars">list of characters to remove from the string</param>
        /// <example>
        /// string s = "abcde";
        /// 
        /// s = s.Strip('a', 'd');  //s becomes 'bce;
        /// </example>
        /// <returns></returns>
        public static string Strip(this string s, params char[] chars)
        {
            foreach (char c in chars)
            {
                s = s.Replace(c.ToString(), "");
            }

            return s;
        }
        /// <summary>
        /// Strip a string of the specified substring.
        /// </summary>
        /// <param name="s">the string to process</param>
        /// <param name="subString">substring to remove</param>
        /// <example>
        /// string s = "abcde";
        /// 
        /// s = s.Strip("bcd");  //s becomes 'ae;
        /// </example>
        /// <returns></returns>
        public static string Strip(this string s, string subString)
        {
            s = s.Replace(subString, "");

            return s;
        }
        #endregion

        #region Encryption

        /// <summary>
        /// Encryptes a string using the supplied key. Encoding is done using RSA encryption.
        /// </summary>
        /// <param name="stringToEncrypt">String that must be encrypted.</param>
        /// <param name="key">Encryptionkey.</param>
        /// <returns>A string representing a byte array separated by a minus sign.</returns>
        /// <exception cref="ArgumentException">Occurs when stringToEncrypt or key is null or empty.</exception>
        public static string Encrypt(this string stringToEncrypt, string key)
        {
            if (string.IsNullOrEmpty(stringToEncrypt))
            {
                throw new ArgumentException("An empty string value cannot be encrypted.");
            }

            if (string.IsNullOrEmpty(key))
            {
                throw new ArgumentException("Cannot encrypt using an empty key. Please supply an encryption key.");
            }

            CspParameters cspp = new CspParameters();
            cspp.KeyContainerName = key;

            using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cspp))
            {
                rsa.PersistKeyInCsp = true;

                byte[] bytes = rsa.Encrypt(System.Text.UTF8Encoding.UTF8.GetBytes(stringToEncrypt), true);

                return BitConverter.ToString(bytes);
            }
        }

        /// <summary>
        /// Decryptes a string using the supplied key. Decoding is done using RSA encryption.
        /// </summary>
        /// <param name="stringToDecrypt">String that must be decrypted.</param>
        /// <param name="key">Decryptionkey.</param>
        /// <returns>The decrypted string or null if decryption failed.</returns>
        /// <exception cref="ArgumentException">Occurs when stringToDecrypt or key is null or empty.</exception>
        public static string Decrypt(this string stringToDecrypt, string key)
        {
            string result = null;

            if (string.IsNullOrEmpty(stringToDecrypt))
            {
                throw new ArgumentException("An empty string value cannot be encrypted.");
            }

            if (string.IsNullOrEmpty(key))
            {
                throw new ArgumentException("Cannot decrypt using an empty key. Please supply a decryption key.");
            }

            try
            {
                CspParameters cspp = new CspParameters();
                cspp.KeyContainerName = key;

                using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cspp))
                {
                    rsa.PersistKeyInCsp = true;

                    string[] decryptArray = stringToDecrypt.Split(new string[] { "-" }, StringSplitOptions.None);
                    byte[] decryptByteArray = Array.ConvertAll<string, byte>(decryptArray, (s => Convert.ToByte(byte.Parse(s, System.Globalization.NumberStyles.HexNumber))));


                    byte[] bytes = rsa.Decrypt(decryptByteArray, true);

                    result = System.Text.UTF8Encoding.UTF8.GetString(bytes);
                }

            }
            finally
            {
                // no need for further processing
            }

            return result;
        }

        #endregion

        #region Occurences

        public static int CountOccurences(this string me, string substring)
        {
            int count = 0, n = 0;

            while ((n = me.IndexOf(substring, n, StringComparison.InvariantCulture)) != -1)
            {
                n += substring.Length;
                ++count;
            }

            return count;
        }

        #endregion

        #region Left / Right

        public static string Left(this string me, int length)
        {
            length = Math.Max(length, 0);

            if (me.Length > length)
            {
                return me.Substring(0, length);
            }
            else
            {
                return me;
            }
        }

        public static string Right(this string me, int length)
        {
            length = Math.Max(length, 0);

            if (me.Length > length)
            {
                return me.Substring(me.Length - length, length);
            }
            else
            {
                return me;
            }
        }

        #endregion

        /// <summary>
        /// Replaces multiple concurrent spaces in string with single spaces
        /// </summary>        
        /// <returns></returns>
        public static string RemoveExcessSpacing(this string me)
        {
            while (me.CountOccurences("  ") > 0) me = me.Replace("  ", " ");

            return me.RemoveExcessSpacing(false);
        }

        /// <summary>
        /// Replaces multiple concurrent spaces in string with single spaces
        /// </summary>
        /// <param name="trim">Perform trim operation on resulting string</param>
        /// <returns></returns>
        public static string RemoveExcessSpacing(this string me, bool trim)
        {
            while (me.CountOccurences("  ") > 0) me = me.Replace("  ", " ");

            if (trim) me.Trim();

            return me;
        }

        public static string F(this string s, params object[] args)
        {
            return string.Format(s, args);
        }

        public static bool HasValue(this string me)
        {
            return !(string.IsNullOrWhiteSpace(me));
        }

        public static int ParseToInt(this string me)
        {
            return int.Parse(me);
        }

        public static string IfNullOrWhitespace(this string me, string replacement)
        {
            if (string.IsNullOrWhiteSpace(me)) return replacement;

            return me;
        }        
    }

}
